
#include "stdafx.h"
#include "Dx9Capture.h"

#define	ErrorMessage(x)		MessageBox(NULL,x,"Error",MB_OK|MB_ICONERROR)

namespace Screenshot
{
	Dx9Capture::Dx9Capture()
		: g_pD3D(NULL), g_pd3dDevice(NULL)
		, g_pSurface(NULL)
		, ghWnd(NULL)
	{

	}

	Dx9Capture::~Dx9Capture()
	{
		Uninit();
	}


	void Dx9Capture::Init(HWND hWnd)
	{
		D3DDISPLAYMODE	ddm;
		D3DPRESENT_PARAMETERS	d3dpp;

		if((g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
		{
			ErrorMessage("Unable to Create Direct3D ");
			return;
		}

		if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
		{
			ErrorMessage("Unable to Get Adapter Display Mode");
			return;
		}

		ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));

		d3dpp.Windowed=FALSE;
		d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
		d3dpp.BackBufferFormat=ddm.Format;
		d3dpp.BackBufferHeight=ddm.Height;
		d3dpp.BackBufferWidth=ddm.Width;
		d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
		d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
		d3dpp.hDeviceWindow=hWnd;
		d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
		d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;

		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
			&d3dpp,&g_pd3dDevice)))
		{
			ErrorMessage("Unable to Create Device");
			return;
		}

		if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8,
			D3DPOOL_DEFAULT /*D3DPOOL_SCRATCH*/,
			&g_pSurface, NULL)))
		{
			ErrorMessage("Unable to Create Surface");
			return;
		}
	}

	void Dx9Capture::Uninit()
	{
		if(g_pSurface)
		{
			g_pSurface->Release();
			g_pSurface=NULL;
		}
		if(g_pd3dDevice)
		{
			g_pd3dDevice->Release();
			g_pd3dDevice=NULL;
		}
		if(g_pD3D)
		{
			g_pD3D->Release();
			g_pD3D=NULL;
		}

		ghWnd = NULL;
	}

	bool Dx9Capture::IsInit() const
	{
		return (NULL != g_pSurface && NULL != g_pd3dDevice);
	}

	void Dx9Capture::FrontBufferFrame()
	{
		g_pd3dDevice->GetFrontBufferData(0, g_pSurface);			
		D3DXSaveSurfaceToFile("dx9_snapshot_class.bmp",D3DXIFF_BMP,g_pSurface,NULL,NULL);		//Save to File

		//D3DLOCKED_RECT	lockedRect;
		//if(FAILED(g_pSurface->LockRect(&lockedRect,NULL,D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
		//{
		//	ErrorMessage("Unable to Lock Front Buffer Surface");	break;
		//}
		//for(int i=0;i<gScreenRect.bottom;i++)
		//{
		//	memcpy((BYTE*)pBits+(gScreenRect.bottom-i-1)*gScreenRect.right*BITSPERPIXEL/8,(BYTE*)lockedRect.pBits+i*lockedRect.Pitch,gScreenRect.right*BITSPERPIXEL/8);//g_d3dpp.BackBufferHeight*g_d3dpp.BackBufferWidth*4);				
		//}
		//g_pSurface->UnlockRect();
	}

	void Dx9Capture::RenderTargetFrame()
	{
		D3DDISPLAYMODE	ddm;
		g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm);

		HRESULT hr = S_OK;

		IDirect3DSurface9 * pRender = NULL;
		//hr = g_pd3dDevice->CreateRenderTarget(ddm.Width, ddm.Height, ddm.Format, D3DMULTISAMPLE_NONE, 0, FALSE,
		//	&pRender, NULL);
		//if (FAILED(hr))
		//{
		//	ErrorMessage("CreateRenderTarget failed");
		//	return;
		//}

		hr =  g_pd3dDevice->GetRenderTarget(0, &pRender);

		if (FAILED(hr))
		{
			ErrorMessage("GetRenderTarget failed");
			return;
		}		
		
		D3DSURFACE_DESC surf_desc;
		ZeroMemory(&surf_desc, sizeof(surf_desc));
		pRender->GetDesc(&surf_desc);
		if (surf_desc.Width != 1440)
		{

		}

		//IDirect3DSurface9 * pDestTarget = NULL;
		//// create a destination surface.
		//hr = g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width,
		//	ddm.Height,
		//	ddm.Format,
		//	D3DPOOL_SYSTEMMEM,
		//	&pDestTarget,
		//	NULL);
		////copy the render target to the destination surface.
		//hr = g_pd3dDevice->GetRenderTargetData(pRender, pDestTarget);
		//// ret 0x8876086c D3DERR_INVALIDCALL

		D3DXSaveSurfaceToFile("dx9render_snapshot_class.bmp",D3DXIFF_BMP,pRender /*pDestTarget*/,NULL,NULL);		//Save to File

		//pDestTarget->Release();
		pRender->Release();
	}

	void Dx9Capture::BackBufferFrame()
	{
		IDirect3DSurface9 *offscreenSurface = NULL;
		HRESULT hr = g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &offscreenSurface);
		if (FAILED(hr))
		{
			ErrorMessage("GetBackBuffer failed");
			return;
		}
		//offscreenSurface->LockRect();
		D3DXSaveSurfaceToFile("dx9back_snapshot_class.bmp", D3DXIFF_BMP, offscreenSurface, 0, 0);
		if (NULL != offscreenSurface)
		{
			offscreenSurface->Release();
		}
	}

	void Dx9Capture::Render()
	{
		HRESULT	hr;
		if(g_pd3dDevice)
		{
			hr=g_pd3dDevice->TestCooperativeLevel();//Check Device Status - if Alt+tab or some such thing have caused any trouble
			if(hr!=D3D_OK)
			{
				if(hr==D3DERR_DEVICELOST)	return;	//Device is lost - Do not render now 
				if(hr==D3DERR_DEVICENOTRESET)		//Device is ready to be acquired
				{	
					//if(FAILED(Reset()))					
					{		
						//DestroyWindow(ghWnd);		//If Unable to Reset Device - Close the Application
						return;	
					}	
				}
			}
			g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,200),1.0f,0);
			g_pd3dDevice->BeginScene();
			g_pd3dDevice->EndScene();
			g_pd3dDevice->Present(NULL,NULL,NULL,NULL);
		}
	}

	void Dx9Capture::Reset()
	{
		D3DDISPLAYMODE	ddm;
		D3DPRESENT_PARAMETERS	d3dpp;

		if(g_pSurface)														//Release the Surface - we need to get the latest surface
		{
			g_pSurface->Release();
			g_pSurface = NULL;
		}

		if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))	//User might have changed the mode - Get it afresh
		{
			ErrorMessage("Unable to Get Adapter Display Mode");
			return;
		}

		ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));

		d3dpp.Windowed=FALSE;
		d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
		d3dpp.BackBufferFormat=ddm.Format;
		d3dpp.BackBufferHeight=ddm.Height;
		d3dpp.BackBufferWidth=ddm.Width;
		d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
		d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
		d3dpp.hDeviceWindow=ghWnd;
		d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
		d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;

		if(FAILED(g_pd3dDevice->Reset(&d3dpp)))
		{
			ErrorMessage("Unable to Create Device");				//Dont present messages when device is lost
			return;
		}

		if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &g_pSurface, NULL)))
		{
			ErrorMessage("Unable to Create Surface");
			return;
		}
	}
}